package cn.elead.chaos.core.util;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.springframework.aop.framework.AopContext;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

/**
 * Spring Application 工具类
 *
 * @author luopeng
 */
@Component
public final class ApplicationUtils implements BeanFactoryPostProcessor, ApplicationContextAware {

	/**
	 * Spring应用上下文环境
	 */
	private static ConfigurableListableBeanFactory beanFactory;

	private static ApplicationContext applicationContext;

	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
		ApplicationUtils.beanFactory = beanFactory;
	}

	/**
	 * 获取ApplicationContext
	 */
	public static ConfigurableListableBeanFactory getBeanFactory() {
		return beanFactory;
	}

	/**
	 * 获取ApplicationContext
	 */
	public static ApplicationContext getContext() {
		return applicationContext;
	}

	/**
	 * 获取springbean
	 *
	 * @param beanName
	 * @param requiredType
	 * @param <T>
	 * @return
	 */
	public static <T> T getBean(String beanName, Class<T> requiredType) {
		if (containsBean(beanName)) {
			return getBeanFactory().getBean(beanName, requiredType);
		}
		return null;
	}

	/**
	 * 获取springbean
	 *
	 * @param requiredType
	 * @param <T>
	 * @return
	 */
	public static <T> T getBean(Class<T> requiredType) {
		return getBeanFactory().getBean(requiredType);
	}

	/**
	 * 获取springbean
	 *
	 * @param beanName
	 * @param <T>
	 * @return
	 */
	public static <T> T getBean(String beanName) {
		if (containsBean(beanName)) {
			Class<T> type = getType(beanName);
			return getBeanFactory().getBean(beanName, type);
		}
		return null;
	}

	public static <T> List<T> getBeansByType(Class<T> beanSuperClass) {
		Map<String, T> beans = getContext().getBeansOfType(beanSuperClass);
		if (beans.size() > 0) {
			return new ArrayList<T>(beans.values());
		}
		return null;
	}

	public static <T> T getBeanByType(Class<T> beanSuperClass) {
		Map<String, T> beans = getContext().getBeansOfType(beanSuperClass);
		if (beans.size() == 0) {
			return new ArrayList<T>(beans.values()).get(0);
		}
		return null;
	}

	/**
	 * ApplicationContext是否包含该Bean
	 *
	 * @param name
	 * @return
	 */
	public static boolean containsBean(String name) {
		return getBeanFactory().containsBean(name);
	}

	/**
	 * ApplicationContext该Bean是否为单例
	 *
	 * @param name
	 * @return
	 */
	public static boolean isSingleton(String name) {
		return getBeanFactory().isSingleton(name);
	}

	/**
	 * 获取该Bean的Class
	 *
	 * @param name
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <T> Class<T> getType(String name) {
		return (Class<T>) getBeanFactory().getType(name);
	}

	/**
	 * 如果给定的bean名字在bean定义中有别名，则返回这些别名
	 *
	 * @param name
	 * @return
	 * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
	 *
	 */
	public static String[] getAliases(String name) throws NoSuchBeanDefinitionException {
		return beanFactory.getAliases(name);
	}

	/**
	 * 获取aop代理对象
	 * 
	 * @param invoker
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <T> T getAopProxy(T invoker) {
		return (T) AopContext.currentProxy();
	}

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		ApplicationUtils.applicationContext = applicationContext;
	}
}
